﻿#include "logBase.h"

//Disruptor
#include "./disruptor/sequencer.h"

#include "./Mmap.h"

#undef ERROR

const size_t DISMAXSIZE = 16384; //disruptor内的环形缓冲区大小


//日志接收器,继承logSink类即可添加日志落地方向
class logSink
{
public:
	logSink();

	~logSink();

	virtual void logOut(const std::string& log) = 0;
};

//输出到out
class logOutputStdout : public logSink
{
public:
	logOutputStdout() = default;

	void logOut(const std::string& log) override;
};

//以fopen打开文件并写入
class logOutputFile : public logSink
{
public:
	logOutputFile(const std::string& path);

	void logOut(const std::string& log) override;

	~logOutputFile();

private:
	FILE* _file = nullptr;
};

//以Mmap打开文件并写入
class logOutputMmapFile : public logSink
{
public: 
	logOutputMmapFile(const std::string& path);

	void logOut(const std::string& log) override;

	~logOutputMmapFile() = default;
private:
	Mmap _file;
};


//工厂模式
class logSinkFactory
{
public:
	template<typename sinkType, typename ...Args>
	static std::shared_ptr<logSink> create(Args &&...args);
};


/*日志器*/
//设置⽇志器名称，
//设置⽇志输出格式，
//设置落地⽅向，
//且落地⽅向有可能存在多个
//日志输入
//基类
class logger
{
public:
	template<typename ...Args>
	logger(const std::string& loggerName, Args&& ...args);

	void formatChange(const std::string& key, const std::function<std::string(logMsg)>& fun);

	void formatClear();

	void setPattern(const std::string& logFormat);

	template<typename EnumT>
	void enumOutDevice();

	template<typename EnumT>
	void enumRegisterDevice(const std::function<std::string(EnumT)>& infor);

	virtual void operator()(const std::string& data, int level, const std::string& fileName, size_t line) = 0;
protected:
	std::string _loggerName;

	Reformat _reformat;

	std::vector<std::shared_ptr<logSink>> _logSink;
};

//同步日志器
class synchronizeLogger : public logger
{
public:
	template<typename ...Args>
	synchronizeLogger(const std::string& loggerName, Args&& ...args);
	
	void operator()(const std::string& data, int level, const std::string& fileName, size_t line) override;

private:

	std::mutex _mutex;
};

//异步日志器
//双缓冲区
class msgBuffer
{
public:
	using Fun = std::function<void(std::vector<logMsg>&, std::vector<logMsg>::iterator&)>;
	msgBuffer(const Fun& outputCall, size_t maxCount);

	void stop();

	void push(logMsg&& msg);

	~msgBuffer();

private:

	void execute();

private:

	Fun _outputCall;

private:
	size_t _maxCount;

	std::mutex _mutex;

	std::condition_variable _conGet;

	std::condition_variable _conPush;

	std::atomic<bool> _check;

	std::vector<logMsg> _buffer1;

	std::vector<logMsg> _buffer2;

	std::vector<logMsg>::iterator _pushIt;

	std::vector<logMsg>::iterator _getIt;

	std::thread _loop;

};

class asynchronousLogger : public logger
{
public:
	template<typename ...Args>
	asynchronousLogger(size_t maxCount, const std::string& loggerName, Args&& ...args);

	void operator()(const std::string& data, int level, const std::string& fileName, size_t line) override;

	~asynchronousLogger() = default;

private:
	void outputCall(std::vector<logMsg>& t1, std::vector<logMsg>::iterator& t2);

private:

	msgBuffer _buffer;
};

//使用Disruptor框架构建异步日志器
class asyDisruptorLogger : public logger
{
public:
	using seq = disruptor::Sequencer<logMsg, DISMAXSIZE, disruptor::MultiThreadedStrategy<DISMAXSIZE>, disruptor::BlockingStrategy>;

	template<typename ...Args>
	asyDisruptorLogger(const std::string& loggerName, Args&& ...args);

	void operator()(const std::string& data, int level, const std::string& fileName, size_t line) override;

	~asyDisruptorLogger();
private:
	void execute();

private:
	std::shared_ptr<std::array<logMsg, DISMAXSIZE>> _events;

	seq _sequencer;

	disruptor::Sequence _conSeq; //消费者序列

	std::vector<disruptor::Sequence*> _conDeps; //消费者无依赖

	std::unique_ptr<disruptor::SequenceBarrier<disruptor::BlockingStrategy>> _conBarrier;  //序列屏障

	std::thread _thread;
};

template<typename sinkType, typename ...Args>
inline std::shared_ptr<logSink> logSinkFactory::create(Args&& ...args)
{
	return std::make_shared<sinkType>(std::forward<Args>(args)...);
}

template<typename ...Args>
inline logger::logger(const std::string& loggerName, Args && ...args)
	: _logSink({ std::forward<Args>(args)... })
{
	_loggerName = loggerName;

	//注册默认等级
	logEnum::Init().registerDevice<Level>([](const Level& other)->std::string
		{
#define TOSTRING(name) #name

			switch (other)
			{
			case Level::ALL:
				return TOSTRING(ALL);
			case Level::DEBUG:
				return TOSTRING(DEBUG);
			case Level::ERROR:
				return TOSTRING(ERROR);
			case Level::FATAL:
				return TOSTRING(FATAL);
			case Level::INFO:
				return TOSTRING(INFO);
			case Level::OFF:
				return TOSTRING(OFF);
			case Level::WARN:
				return TOSTRING(WARN);
			default:
				return "UNKNOW";
				break;
			}

#undef TOSTRING

			return "UNKNOW";
		});

	//设置默认格式化函数
	_reformat.change("%d", [](const logMsg& log)
		{
			return std::to_string(log._time);
		});
	_reformat.change("%T", [](const logMsg& log)
		{
			return "  ";
		});
	_reformat.change("%t", [](const logMsg& log)
		{
			std::ostringstream oss;
			oss << log._id;  
			return oss.str();
		});
	_reformat.change("%p", [](const logMsg& log)
		{
			return logEnum::Init().toString(static_cast<Level>(log._level));
		});
	_reformat.change("%c", [](const logMsg& log)
		{
			return log._loggerName;
		});
	_reformat.change("%f", [](const logMsg& log)
		{
			return log._fileName;
		});
	_reformat.change("%l", [](const logMsg& log)
		{
			return std::to_string(log._line);
		});
	_reformat.change("%m", [](const logMsg& log)
		{
			return log._data;
		});
	_reformat.change("%n", [](const logMsg& log)
		{
			return "\n";
		});
}

template<typename EnumT>
inline void logger::enumOutDevice()
{
	logEnum::Init().logoutDevice<EnumT>();
}

template<typename EnumT>
inline void logger::enumRegisterDevice(const std::function<std::string(EnumT)>& infor)
{
	logEnum::Init().registerDevice<EnumT>(infor);
}

template<typename ...Args>
inline synchronizeLogger::synchronizeLogger(const std::string& loggerName, Args && ...args)
	: logger(loggerName, std::forward<Args>(args)...)
{

}

template<typename ...Args>
inline asynchronousLogger::asynchronousLogger(size_t maxCount, const std::string& loggerName, Args && ...args)
	: logger(loggerName, std::forward<Args>(args)...)
	, _buffer(std::bind(&asynchronousLogger::outputCall, this, std::placeholders::_1, std::placeholders::_2), maxCount)
{
}

template<typename ...Args>
inline asyDisruptorLogger::asyDisruptorLogger(const std::string& loggerName, Args && ...args)
	: logger(loggerName, std::forward<Args>(args)...)
	, _events(std::make_shared<std::array<logMsg, DISMAXSIZE>>())
	, _sequencer(_events)
{
	_conDeps = { &_conSeq };
	_sequencer.set_gating_sequences(_conDeps);

	_conBarrier = std::make_unique<disruptor::SequenceBarrier<disruptor::BlockingStrategy>>(
		_sequencer.GetWaitStrategySequence(), 
		_sequencer.GetCursorSequence(),
		std::vector<disruptor::Sequence*>{});

	_conSeq.set_sequence(disruptor::kInitialCursorValue);
	_thread = std::thread(&asyDisruptorLogger::execute, this);
}
